/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <mc/exception.h>
#include <mc/filesystem.h>
#include <mc/json.h>
#include <mc/log.h>

#include "devmon/driver_abi.h"
#include "discovery/csr_parser.h"
#include "discovery/object_group.h"
#include "discovery/root_interface.h"

#include "device/manager.h"

namespace devmon {

void root_interface::add_device(const std::string& csr_file, mc::dict connector) {
    auto csr_str = mc::filesystem::read_file(csr_file);
    MC_ASSERT_THROW(csr_str, mc::invalid_arg_exception, "Failed to read csr file: ${file}",
                    ("file", csr_file));
    auto             position          = csr_utils::get_connector_position(connector);
    mc::mutable_dict mutable_connector = connector;
    if (!position.empty()) {
        // 数字类型的Postion需要转换为十六进制格式字符串
        mutable_connector["GroupPosition"] = position;
    }
    device_manager::get_instance().add_device(get_service(), *csr_str, mutable_connector);
    auto csr_data = mc::json::json_decode(*csr_str);
    csr_parser::parse(position, mutable_connector, csr_data.as_dict());
    create_object_group(get_service(), position, connector);
}

void root_interface::remove_device(std::map<std::string, std::string> context, const mc::dict& connector) {
    auto position = utils::get_connector_position(connector);
    if (position.empty()) {
        return;
    }
    device_manager::get_instance().remove_device(connector);
    // 仅当对象已注册时再注销，防止重复注销导致的警告或崩溃
    auto& table = get_service()->get_object_table();
    auto  obj   = table.find_object(mc::engine::by_object_name::field == position);
    if (obj) {
        get_service()->unregister_object("/bmc/dev/ObjectGroup/" + position);
    }
}

object_group_ptr root_interface::create_object_group(mc::engine::service* service,
                                                     const std::string&   position,
                                                     const mc::dict&      connector) {
    auto object_group_ptr = mc::make_shared<object_group>();
    object_group_ptr->set_object_name(position);
    object_group_ptr->set_position(position);
    object_group_ptr->set_object_identifier(
        std::make_tuple(connector.get("SystemId", 0).as<uint8_t>(),
                        connector.get("ManagerId", "").as<std::string>(),
                        connector.get("ChassisId", "").as<std::string>(), position));
    object_group_ptr->init(position, utils::get_sys_ms() - m_ticks,
                           connector.get("Slot", 0).as<uint8_t>());
    service->register_object(object_group_ptr);
    return object_group_ptr;
}

} // namespace devmon

MC_REFLECT(devmon::root_interface, ((add_device, "AddDevice"))((remove_device, "RemoveDevice")))
